//
//  KTableData.m
//  MengLiao
//
//  Created by xiuxin on 2022/7/15.
//  Copyright © 2022 ZHBen. All rights reserved.
//
#import "KTableData.h"
#import <objc/runtime.h>

@interface UITableViewCell (KTableData)

@end

@implementation UITableViewCell (KTableData)

- (dispatch_block_t)kConfigBlock
{
    return objc_getAssociatedObject(self, @selector(kConfigBlock));
}

- (void)setKConfigBlock:(dispatch_block_t)block
{
    objc_setAssociatedObject(self, @selector(kConfigBlock), block, OBJC_ASSOCIATION_COPY);
}

@end

@implementation UITableView (KTableData)

- (KTableData *)kTableData:(id)delegate
{
    KTableData * tableData = objc_getAssociatedObject(self, @selector(kTableData));
    if (!tableData)
    {
        tableData = [[KTableData alloc] initWithDelegate:delegate dataSource:nil];
        [tableData applyToTable:self];
        self.kTableData = tableData;
    }
    return tableData;
}

- (KTableData *)kTableData
{
    KTableData * tableData = objc_getAssociatedObject(self, _cmd);
    if (!tableData)
    {
        tableData = [[KTableData alloc] init];
        [tableData applyToTable:self];
        self.kTableData = tableData;
    }
    return tableData;
}

- (void)setKTableData:(KTableData *)kTableData
{
    objc_setAssociatedObject(self, @selector(kTableData), kTableData, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (id<KTableConfigure>)configure
{
    return (id<KTableConfigure>)self.kTableData;
}

- (id<KTableDataSource>)dataConfig
{
    return (id<KTableDataSource>)self.kTableData;
}

- (id<KTableOperation>)operation
{
    return (id<KTableOperation>)self.kTableData;
}

@end

@interface KCellModelConfig (KTableData)

@property (strong,nonatomic) NSString * reuseIdentfier;

@property (strong,nonatomic) Class cellClass;

@end

@interface KSectionModelConfig (KTableData)

@property (strong,nonatomic) Class sectionViewClass;

@property (strong,nonatomic) NSString * reuseIdentfier;

@end

@interface KTableData()

@property (nonatomic) BOOL noCellSelectionStyle;

@property (weak,nonatomic) UITableView * table;

@property (nonatomic) UITableViewRowAnimation rowAnimation;

@property (weak,nonatomic) id outDelegate;
@property (weak,nonatomic) id outDataSource;

@property (strong,nonatomic) NSMutableArray * cellConfigList;
@property (strong,nonatomic) NSMutableArray * sectionHeaderConfigList;
@property (strong,nonatomic) NSMutableArray * sectionFooterConfigList;

@property (strong,nonatomic) NSMutableDictionary * sectionDict;
@property (strong,nonatomic) NSMutableDictionary * sectionModelDict;

@property (nonatomic) BOOL enableEdit;
@property (nonatomic) BOOL enableIndexTitles;

@end

@implementation KTableData

- (instancetype)init
{
    return [self initWithDelegate:nil dataSource:nil];
}

- (instancetype)initWithDelegate:(id)delegate dataSource:(id)dataSource
{
    self = [super init];
    if (self)
    {
        _outDelegate = delegate;
        _outDataSource = dataSource;
        
        _cellConfigList = [NSMutableArray array];
        _sectionHeaderConfigList = [NSMutableArray array];
        _sectionFooterConfigList = [NSMutableArray array];
        
        _sectionDict = [NSMutableDictionary dictionary];
        _sectionModelDict = [NSMutableDictionary dictionary];
        _rowAnimation = UITableViewRowAnimationFade;

    }
    return self;
}

- (void)setDelegate:(id)delegate
{
    _outDelegate = delegate;
    _table.delegate = nil;
    _table.delegate = self;
}

#pragma mark KTableConfigure
- (id<KTableConfigure>)configure
{
    return (id<KTableConfigure>)self;
}

- (void)registerCellList:(NSArray<Class> *)cellList delegate:(id)delegate
{
    for (Class cellClass in cellList)
    {
        if ([(id)cellClass respondsToSelector:@selector(registerToTable:)])
        {
            [(id)cellClass performSelector:@selector(registerToTable:) withObject:self.table];
        }
        else if ([(id)cellClass respondsToSelector:@selector(registerToTable:delegate:)])
        {
            [(id)cellClass performSelector:@selector(registerToTable:delegate:) withObject:self.table withObject:delegate];
        }
    }
}

- (void)registerCellClass:(Class)aClass config:(KCellModelConfig *)config
{
    [self registerClass:aClass forCellReuseIdentifier:nil config:config];
}

- (void)registerSectionHeaderClass:(Class)aClass config:(KSectionModelConfig *)config
{
    [self registerClass:aClass forSectionHeaderViewReuseIdentifier:nil config:config];
}

- (void)registerSectionFooterClass:(Class)aClass config:(KSectionModelConfig *)config
{
    [self registerClass:aClass forSectionFooterViewReuseIdentifier:nil config:config];
}

- (void)registerClass:(Class)aClass forCellReuseIdentifier:(NSString *)identifier config:(KCellModelConfig *)config
{
    if (aClass)
    {
        config = config ? [config copy] : [KCellModelConfig new];
        identifier = identifier ?: NSStringFromClass(aClass);
        config.cellClass = aClass;
        config.reuseIdentfier = identifier;
        [self.cellConfigList removeObject:config];
        [self.cellConfigList addObject:config];
        if (_table)
        {
            [_table registerClass:aClass forCellReuseIdentifier:identifier];
            [self sortConfigList:self.cellConfigList];
        }
    }
}

- (void)registerClass:(Class)aClass forSectionHeaderViewReuseIdentifier:(NSString *)identifier config:(KSectionModelConfig *)config
{
    if (aClass)
    {
        config = config ? [config copy] : [KCellModelConfig new];
        identifier = identifier ?: NSStringFromClass(aClass);
        config.sectionViewClass = aClass;
        config.reuseIdentfier = identifier;
        [self.sectionHeaderConfigList addObject:config];
        if (config.section != nil)
        {
            [[self autoSectionModelForSection:config.section.integerValue] setKSectionHeaderIdentifier:identifier];
        }
        if (_table)
        {
            [_table registerClass:aClass forHeaderFooterViewReuseIdentifier:identifier];
            [self sortConfigList:self.sectionHeaderConfigList];
        }
    }
}

- (void)registerClass:(Class)aClass forSectionFooterViewReuseIdentifier:(NSString *)identifier config:(KSectionModelConfig *)config
{
    if (aClass)
    {
        config = config ? [config copy] : [KCellModelConfig new];
        identifier = identifier ?: NSStringFromClass(aClass);
        config.sectionViewClass = aClass;
        config.reuseIdentfier = identifier;
        [self.sectionFooterConfigList addObject:config];
        if (config.section != nil)
        {
            [[self autoSectionModelForSection:config.section.integerValue] setKSectionFooterIdentifier:identifier];
        }
        if (_table)
        {
            [_table registerClass:aClass forHeaderFooterViewReuseIdentifier:identifier];
            [self sortConfigList:self.sectionFooterConfigList];
        }
    }
}

- (id)autoSectionModelForSection:(NSInteger)section
{
    id sectionModel = [self.dataConfig sectionModelForSection:section];
    if (!sectionModel)
    {
        sectionModel = [KCommonTableModel sectionModel:nil headerIdentifier:nil footerIdentifier:nil];
        [self.dataConfig setSectionModel:sectionModel forSection:section];
    }
    return sectionModel;
}

- (KCellModelConfig *)cellConfigForModel:(id)model
{
    NSString * identifier = [model kCellIdentifier];
    if (identifier)
    {
        NSArray * configList = [self configListWithIdentifier:identifier fromList:self.cellConfigList];
        if (configList.count == 1)
        {
            return [configList firstObject];
        }
        for (KCellModelConfig * config in configList)
        {
            if ([config.reuseIdentfier isEqualToString:identifier] && (!config.modelClass || [model isKindOfClass:config.modelClass]))
            {
                return config;
            }
        }
    }
    else
    {
        for (KCellModelConfig * config in self.cellConfigList)
        {
            if ([model isKindOfClass:config.modelClass])
            {
                return config;
            }
        }
    }
    return nil;
}

- (NSArray *)configListWithIdentifier:(NSString *)identifier fromList:(NSArray *)list
{
    NSMutableArray * array = [NSMutableArray array];
    for (id config in list)
    {
        if ([[config reuseIdentfier] isEqualToString:identifier])
        {
            [array addObject:config];
        }
    }
    return array;
}

- (KSectionModelConfig *)sectionHeaderConfigForModel:(id)model
{
    NSString * identifier = [model kSectionHeaderIdentifier];
    if (identifier)
    {
        NSArray * configList = [self configListWithIdentifier:identifier fromList:self.sectionHeaderConfigList];
        if (configList.count == 1)
        {
            return [configList objectAtIndex:0];
        }
        for (KSectionModelConfig * config in configList)
        {
            if ([config.reuseIdentfier isEqualToString:identifier] && (!config.modelClass || [model isKindOfClass:config.modelClass]))
            {
                return config;
            }
        }
    }
    else
    {
        for (KSectionModelConfig * config in self.sectionHeaderConfigList)
        {
            if ([model isKindOfClass:config.modelClass])
            {
                return config;
            }
        }
    }
    return nil;
}

- (KSectionModelConfig *)sectionFooterConfigForModel:(id)model
{
    NSString * identifier = [model kSectionFooterIdentifier];
    if (identifier)
    {
        NSArray * configList = [self configListWithIdentifier:identifier fromList:self.sectionFooterConfigList];
        if (configList.count == 1)
        {
            return [configList objectAtIndex:0];
        }
        for (KSectionModelConfig * config in configList)
        {
            if ([config.reuseIdentfier isEqualToString:identifier] && (!config.modelClass || [model isKindOfClass:config.modelClass]))
            {
                return config;
            }
        }
    }
    else
    {
        for (KSectionModelConfig * config in self.sectionFooterConfigList)
        {
            if ([model isKindOfClass:config.modelClass])
            {
                return config;
            }
        }
    }
    return nil;
}

- (void)applyToTable:(UITableView *)tableView
{
    [self sortConfigList:self.cellConfigList];
    [self sortConfigList:self.sectionHeaderConfigList];
    [self sortConfigList:self.sectionFooterConfigList];
    _table = tableView;
    [self regiserClassForTable];
    _table.delegate = self;
    _table.dataSource = self;
    _table.kTableData = self;
}

- (void)sortConfigList:(NSMutableArray *)configList
{
    NSComparator comparator = ^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
        if (![obj1 modelClass])
        {
            return NSOrderedDescending;
        }
        if (![obj2 modelClass])
        {
            return NSOrderedAscending;
        }
        if ([[obj1 modelClass] isSubclassOfClass:[obj2 modelClass]])
        {
            return NSOrderedAscending;
        }
        return NSOrderedDescending;
    };
    [configList sortUsingComparator:comparator];
}

- (void)regiserClassForTable
{
    for (KCellModelConfig * config in self.cellConfigList)
    {
        [_table registerClass:config.cellClass forCellReuseIdentifier:config.reuseIdentfier];
    }
    for (KSectionModelConfig * config in self.sectionHeaderConfigList)
    {
        [_table registerClass:config.sectionViewClass forHeaderFooterViewReuseIdentifier:config.reuseIdentfier];
    }
    for (KSectionModelConfig * config in self.sectionFooterConfigList)
    {
        [_table registerClass:config.sectionViewClass forHeaderFooterViewReuseIdentifier:config.reuseIdentfier];
    }
}

#pragma mark KTableDataSource
- (id<KTableDataSource>)dataConfig
{
    return (id<KTableDataSource>)self;
}

- (void)setModelList:(NSArray *)modelList forSection:(NSInteger)section
{
    NSString * key = [NSString stringWithFormat:@"%ld",section];
    NSMutableArray * dataArray = [NSMutableArray arrayWithArray:modelList];
    for (NSInteger index = _sectionDict.count; index < section; index++)
    {
        NSString * sectionKey = [NSString stringWithFormat:@"%ld",index];
        _sectionDict[sectionKey] = [NSMutableArray array];
    }
    _sectionDict[key] = dataArray;
}

- (void)setSectionModel:(id)model forSection:(NSInteger)section
{
    NSString * key = [NSString stringWithFormat:@"%ld",section];
    if (model)
    {
        _sectionModelDict[key] = model;
    }
    else
    {
        [_sectionModelDict removeObjectForKey:key];
    }
}

- (NSMutableArray *)dataArrayOfSection:(NSInteger)section
{
    return [_sectionDict objectForKey:[NSString stringWithFormat:@"%ld",section]];
}

- (NSArray *)filterRepeatObjects:(NSArray *)objects section:(NSInteger)section
{
    if (objects.count == 0)
    {
        return nil;
    }
    NSMutableArray * mArray = [objects mutableCopy];
    NSMutableArray * dataArray = [self dataArrayOfSection:section];
    for (id object in dataArray)
    {
        NSInteger index = [mArray indexOfObject:object];
        if (index != NSNotFound)
        {
            [mArray removeObjectAtIndex:index];
        }
    }
    return mArray;
}

- (NSArray *)indexPathsWithIndexSet:(NSIndexSet *)indexSet section:(NSInteger)section
{
    NSMutableArray * array = [NSMutableArray arrayWithCapacity:indexSet.count];
    [indexSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL * _Nonnull stop) {
        [array addObject:[NSIndexPath indexPathForRow:idx inSection:section]];
    }];
    return array;
}

- (NSIndexPath *)indexPathForModel:(id)model
{
    for (NSString * key in _sectionDict.allKeys)
    {
        NSInteger section = [key integerValue];
        NSArray * modelList = _sectionDict[key];
        NSInteger row = [modelList indexOfObject:model];
        if (row != NSNotFound)
        {
            return [NSIndexPath indexPathForRow:row inSection:section];
        }
    }
    return nil;
}

- (NSIndexPath *)indexPathForModel:(id)model section:(NSInteger)section
{
    NSArray * modelList = _sectionDict[[NSString stringWithFormat:@"%ld",section]];
    if (modelList.count > 0)
    {
        NSInteger row = [modelList indexOfObject:model];
        if (row != NSNotFound)
        {
            return [NSIndexPath indexPathForRow:row inSection:section];
        }
    }
    return nil;
}

- (NSArray *)indexPathsWithRange:(NSRange)range section:(NSInteger)section
{
    NSMutableArray * array = [NSMutableArray arrayWithCapacity:range.length];
    for (NSInteger index = 0; index < range.length; index++)
    {
        [array addObject:[NSIndexPath indexPathForRow:index + range.location inSection:section]];
    }
    return array;
}

- (id)modelAtIndexPath:(NSIndexPath *)indexPath
{
    NSArray * modelArray = [_sectionDict objectForKey:[NSString stringWithFormat:@"%ld",indexPath.section]];
    return modelArray.count > indexPath.row ? modelArray[indexPath.row] : nil;
}

- (id)sectionModelForSection:(NSInteger)section
{
    return [_sectionModelDict objectForKey:[NSString stringWithFormat:@"%ld",section]];
}

- (NSInteger)sectionForSectionModel:(id)sectionModel
{
    if (sectionModel != nil)
    {
        NSArray<NSString *> * allKeys = [_sectionModelDict allKeysForObject:sectionModel];
        if (allKeys.count == 1)
        {
            return [[allKeys firstObject] integerValue];
        }
    }
    return NSNotFound;
}

- (void)removeModelAtIndexPath:(NSIndexPath *)indexPath
{
    NSMutableArray * dataArray = [self dataArrayOfSection:indexPath.section];
    [dataArray removeObjectAtIndex:indexPath.row];
}

- (void)insertModel:(id)model toIndexPath:(NSIndexPath *)indexPath
{
    NSMutableArray * dataArray = [self dataArrayOfSection:indexPath.section];
    [dataArray insertObject:model atIndex:indexPath.row];
}

- (void)replaceModel:(id)model toIndexPath:(NSIndexPath *)indexPath
{
    NSMutableArray * dataArray = [self dataArrayOfSection:indexPath.section];
    [dataArray replaceObjectAtIndex:indexPath.row withObject:model];
}

- (NSIndexPath *)replaceModel:(id)oldModel withModel:(id)newModel section:(NSInteger)section
{
    if (oldModel && newModel)
    {
        if (section >= 0)
        {
            NSMutableArray * dataArray = [self dataArrayOfSection:section];
            if (dataArray.count > 0)
            {
                NSInteger row = [dataArray indexOfObject:oldModel];
                if (row != NSNotFound)
                {
                    [dataArray replaceObjectAtIndex:row withObject:newModel];
                    return [NSIndexPath indexPathForRow:row inSection:section];
                }
            }
        }
        else
        {
            NSIndexPath * indexPath = [self indexPathForModel:oldModel];
            if (indexPath)
            {
                NSMutableArray * dataArray = [self dataArrayOfSection:indexPath.section];
                [dataArray replaceObjectAtIndex:indexPath.row withObject:newModel];
                return indexPath;
            }
            
        }
    }
    return nil;
}

- (void)moveModelAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
    id model = [self modelAtIndexPath:fromIndexPath];
    [self removeModelAtIndexPath:fromIndexPath];
    [self insertModel:model toIndexPath:toIndexPath];
}

- (id)modelAtSection:(NSInteger)section
{
    return _sectionModelDict[[NSString stringWithFormat:@"%ld",section]];
}

- (void)cleanData
{
    _sectionDict = [NSMutableDictionary dictionary];
}

- (void)cleanSectionData
{
    _sectionModelDict = [NSMutableDictionary dictionary];
}

- (NSArray<NSIndexPath *> *)addObjects:(NSArray *)objects afterSection:(NSInteger)section checkRepeat:(BOOL)checkRepeat
{
    NSMutableArray * dataArray = [self dataArrayOfSection:section];
    if (dataArray.count == 0)
    {
        [self setModelList:objects forSection:section];
        return nil;
    }
    if (checkRepeat)
    {
        objects = [self filterRepeatObjects:objects section:section];
    }
    if ([objects count] > 0)
    {
        NSMutableArray * dataArray = [self dataArrayOfSection:section];
        NSRange range = NSMakeRange(dataArray.count, objects.count);
        [dataArray insertObjects:objects atIndexes:[NSIndexSet indexSetWithIndexesInRange:range]];
        return [self indexPathsWithRange:range section:section];
    }
    return nil;
}

- (NSArray<NSIndexPath *> *)addObjects:(NSArray *)objects beforeSection:(NSInteger)section checkRepeat:(BOOL)checkRepeat
{
    NSMutableArray * dataArray = [self dataArrayOfSection:section];
    if (dataArray.count == 0)
    {
        [self setModelList:objects forSection:section];
        return nil;
    }
    if (checkRepeat)
    {
        objects = [self filterRepeatObjects:objects section:section];
    }
    if (objects.count > 0)
    {
        NSMutableArray * dataArray = [self dataArrayOfSection:section];
        NSRange range = NSMakeRange(0, objects.count);
        [dataArray insertObjects:objects atIndexes:[NSIndexSet indexSetWithIndexesInRange:range]];
        return [self indexPathsWithRange:range section:section];
    }
    return nil;
}

#pragma mark KTableOperation
- (id<KTableOperation>)operation
{
    return (id<KTableOperation>)self;
}

- (void)beginUpdates
{
    [_table beginUpdates];
}

- (void)endUpdates
{
    [_table endUpdates];
}

- (void)reloadData
{
    [_table reloadData];
}

- (void)removeObjects:(NSArray *)objects inSection:(NSInteger)section
{
    NSMutableArray * dataArray = [self dataArrayOfSection:section];
    NSMutableIndexSet * indeSet = [NSMutableIndexSet indexSet];
    for (NSInteger index = dataArray.count - 1; index >= 0; index--)
    {
        id object = dataArray[index];
        if ([objects containsObject:object])
        {
            [indeSet addIndex:index];
        }
    }
    [self removeObjectsWithIndexSet:indeSet inSection:section];
}

- (void)removeObject:(id)object inSection:(NSInteger)section
{
    NSMutableArray * dataArray = [self dataArrayOfSection:section];
    if (dataArray.count > 0)
    {
        NSInteger index = [dataArray indexOfObject:object];
        if (index != NSNotFound)
        {
            [dataArray removeObjectAtIndex:index];
            [_table deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:index inSection:section]] withRowAnimation:_rowAnimation];
        }
    }
}

- (void)removeObjectsWithIndexSet:(NSIndexSet *)indexSet inSection:(NSInteger)section
{
    NSMutableArray * dataArray = [self dataArrayOfSection:section];
    //防止crash
    __block BOOL valide = YES;
    [indexSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL * _Nonnull stop) {
        if (dataArray.count <= idx)
        {
            valide = NO;
            *stop = YES;
        }
    }];
    if (!valide)
    {
        return;
    }
    [dataArray removeObjectsAtIndexes:indexSet];
    [_table deleteRowsAtIndexPaths:[self indexPathsWithIndexSet:indexSet section:section] withRowAnimation:_rowAnimation];
}

- (void)insertObject:(id)object atIndex:(NSInteger)index section:(NSInteger)section
{
    NSMutableArray * dataArray = [self dataArrayOfSection:section];
    [dataArray insertObject:object atIndex:index];
    [_table insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:index inSection:section]] withRowAnimation:_rowAnimation];
}

- (void)insertSection:(NSInteger)section objects:(NSArray *)objects
{
    if (![_sectionDict.allKeys containsObject:[NSString stringWithFormat:@"%d",(int)section]])
    {
        if (_sectionDict.allKeys.count == 0)
        {
            [self setModelList:objects forSection:section];
            [_table reloadData];
        }
        else
        {
            [self setModelList:objects forSection:section];
            [_table insertSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:_rowAnimation];
        }
    }
    else
    {
        [self setModelList:objects forSection:section];
        [_table reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:_rowAnimation];
    }
}

- (void)insertObjects:(NSArray *)objects inRange:(NSRange)range section:(NSInteger)section
{
    NSMutableArray * dataArray = [self.dataConfig dataArrayOfSection:section];
    [dataArray insertObjects:objects atIndexes:[NSIndexSet indexSetWithIndexesInRange:range]];
    [self.dataConfig setModelList:dataArray forSection:section];
    
    NSArray<NSIndexPath *> * indexPathList = [self indexPathsWithRange:range section:section];
    [_table insertRowsAtIndexPaths:indexPathList withRowAnimation:_rowAnimation];
}

- (void)removeObjectsInRange:(NSRange)range section:(NSInteger)section
{
    NSMutableArray * dataArray = [self.dataConfig dataArrayOfSection:section];
    [dataArray removeObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:range]];
    [self.dataConfig setModelList:dataArray forSection:section];
    
    NSArray<NSIndexPath *> * indexPathList = [self indexPathsWithRange:range section:section];
    [_table deleteRowsAtIndexPaths:indexPathList withRowAnimation:_rowAnimation];
}

- (void)insertObjects:(NSArray *)objects beforeSection:(NSInteger)section checkRepeat:(BOOL)checkRepeat
{
    if (objects.count == 0)
    {
        return;
    }
    NSMutableArray * dataArray = [self dataArrayOfSection:section];
    if (dataArray.count == 0)
    {
        [self insertSection:section objects:objects];
    }
    else
    {
        NSArray<NSIndexPath *> * indexPaths = [self addObjects:objects beforeSection:section checkRepeat:checkRepeat];
        if (indexPaths.count > 0)
        {
            [_table insertRowsAtIndexPaths:indexPaths withRowAnimation:_rowAnimation];
        }
    }
}

- (void)insertObjects:(NSArray *)objects afterSection:(NSInteger)section checkRepeat:(BOOL)checkRepeat
{
    if (objects.count == 0)
    {
        return;
    }
    NSMutableArray * dataArray = [self dataArrayOfSection:section];
    if (dataArray.count == 0)
    {
        [self insertSection:section objects:objects];
    }
    else
    {
        NSArray<NSIndexPath *> * indexPaths = [self addObjects:objects afterSection:section checkRepeat:checkRepeat];
        if (indexPaths.count > 0)
        {
            [_table insertRowsAtIndexPaths:indexPaths withRowAnimation:_rowAnimation];
        }
    }
}

- (void)insertObjects:(NSArray *)objects afterObject:(id)object section:(NSInteger)section checkRepeat:(BOOL)checkRepeat
{
    if (objects.count == 0)
    {
        return;
    }
    if (checkRepeat)
    {
        objects = [self filterRepeatObjects:objects section:section];
    }
    if ([objects count] > 0 && object != nil)
    {
        NSMutableArray * dataArray = [self dataArrayOfSection:section];
        if (dataArray != nil)
        {
            NSInteger index = [dataArray indexOfObject:object];
            if (index == NSNotFound || index == dataArray.count - 1)
            {
                [self insertObjects:objects afterSection:section checkRepeat:NO];
            }
            else
            {
                NSRange range = NSMakeRange(index + 1, objects.count);
                [dataArray insertObjects:objects atIndexes:[NSIndexSet indexSetWithIndexesInRange:range]];
                [_table insertRowsAtIndexPaths:[self indexPathsWithRange:range section:section] withRowAnimation:_rowAnimation];
            }
        }
    }
}

- (void)insertObjects:(NSArray *)objects beforeObject:(id)object section:(NSInteger)section checkRepeat:(BOOL)checkRepeat
{
    if (objects.count == 0)
    {
        return;
    }
    if (checkRepeat)
    {
        objects = [self filterRepeatObjects:objects section:section];
    }
    if ([objects count] > 0 && object)
    {
        NSMutableArray * dataArray = [self dataArrayOfSection:section];
        if (dataArray != nil)
        {
            NSInteger index = [dataArray indexOfObject:object];
            if (index == NSNotFound)
            {
                [self insertObjects:objects afterSection:section checkRepeat:NO];
            }
            else
            {
                NSRange range = NSMakeRange(index, objects.count);
                [dataArray insertObjects:objects atIndexes:[NSIndexSet indexSetWithIndexesInRange:range]];
                [_table insertRowsAtIndexPaths:[self indexPathsWithRange:range section:section] withRowAnimation:_rowAnimation];
            }
        }
    }
}

- (void)reloadModel:(id)model section:(NSInteger)section
{
    if (model)
    {
        [self reloadModelList:@[model] section:section];
    }
}

- (void)reloadModel:(id)model atIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath && ![self loadModel:model forIndexPath:indexPath replace:YES])
    {
        [_table reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:_rowAnimation];
    }
}

- (void)reloadModelList:(NSArray *)modelList section:(NSInteger)section
{
    if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.3)
    {
        if (_table.indexPathsForVisibleRows.count > 0)
        {
            [_table reloadRowsAtIndexPaths:_table.indexPathsForVisibleRows withRowAnimation:UITableViewRowAnimationNone];
        }
        return;
    }
    NSMutableArray * indexPaths = [NSMutableArray arrayWithCapacity:modelList.count];
    for (id model in modelList)
    {
        NSIndexPath * indexPath = section >= 0 ? [self indexPathForModel:model section:section] : [self indexPathForModel:model];
        if (indexPath && ![self loadModel:model forIndexPath:indexPath replace:NO])
        {
            [indexPaths addObject:indexPath];
        }
    }
    if (indexPaths.count > 0)
    {
        [_table reloadRowsAtIndexPaths:indexPaths withRowAnimation:_rowAnimation];
    }
}

- (BOOL)loadModel:(id)model forIndexPath:(NSIndexPath *)indexPath replace:(BOOL)replace
{
    if (replace)
    {
        [self replaceModel:model toIndexPath:indexPath];
    }
    if ([_table.indexPathsForVisibleRows containsObject:indexPath])
    {
        UITableViewCell * cell = [_table cellForRowAtIndexPath:indexPath];
        if (cell)
        {
            KCellModelConfig * config = [self cellConfigForModel:model];
            CGFloat rowHeight = [model kCellHeight] != nil ? [[model kCellHeight] floatValue] : config.rowHeight;
            if (fabs(cell.height - rowHeight) <= 1)
            {
                NSString * reuseIdentifier = [model kCellIdentifier] ?: config.reuseIdentfier;
                if ([reuseIdentifier isEqualToString:cell.reuseIdentifier])
                {
                    KCellConfigBlock configBlock = [model kCellConfigBlock] ?: config.configBlock;
                    KExecuteBlock(configBlock,cell,model,indexPath);
                    return YES;
                }
            }
        }
    }
    return NO;
}

- (void)reloadVisibleRows
{
    NSArray<NSIndexPath *> * indexPathList = [self.table indexPathsForVisibleRows];
    if (indexPathList.count > 0)
    {
        [self.table reloadRowsAtIndexPaths:indexPathList withRowAnimation:UITableViewRowAnimationNone];
    }
}

- (NSIndexPath *)refreshModel:(id)model section:(NSInteger)section
{
    NSIndexPath * indexPath = [self indexPathForModel:model section:section];
    [self.table reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
    return indexPath;
}

- (NSIndexPath *)refreshModel:(id)model
{
    NSIndexPath * indexPath = [self indexPathForModel:model];
    [self.table reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
    return indexPath;
}

- (void)reloadSectionModel:(id)sectionModel section:(NSInteger)section
{
    [self setSectionModel:sectionModel forSection:section];
    [self refreshSectionModelAtSection:section];
}

- (void)refreshSectionModel:(id)sectionModel
{
    NSInteger section = [self sectionForSectionModel:sectionModel];
    [self refreshSectionModelAtSection:section];
}

- (void)refreshSectionModelAtSection:(NSInteger)section
{
    id sectionModel = [self sectionModelForSection:section];
    [UIView setAnimationsEnabled:NO];
    [self.table beginUpdates];
    KSectionModelConfig * headerConfig = [self sectionHeaderConfigForModel:sectionModel];
    if (headerConfig != nil)
    {
        UITableViewHeaderFooterView * headerView = [self.table headerViewForSection:section];
        if (headerView != nil)
        {
            KExecuteBlock(headerConfig.configBlock,headerView,sectionModel,section);
        }
    }
    KSectionModelConfig * footerConfig = [self sectionFooterConfigForModel:sectionModel];
    if (footerConfig != nil)
    {
        UITableViewHeaderFooterView * footerView = [self.table footerViewForSection:section];
        if (footerView != nil)
        {
            KExecuteBlock(footerConfig.configBlock,footerView,sectionModel,section);
        }
    }
    [self.table endUpdates];
    [UIView setAnimationsEnabled:YES];
}

- (void)reloadModel:(id)oldModel replace:(id)newModel section:(NSInteger)section
{
    if (oldModel && newModel)
    {
        [self reloadModelList:@[oldModel] replace:@[newModel] section:section];
    }
}

- (void)reloadModelList:(NSArray *)modelList replace:(NSArray *)newModelList section:(NSInteger)section
{
    NSMutableArray * indexPaths = [NSMutableArray arrayWithCapacity:modelList.count];
    for (NSInteger index = 0; index < modelList.count; index++)
    {
        id oldModel = modelList[index];
        id newModel = newModelList[index];
        NSIndexPath * indexPath = [self.dataConfig replaceModel:oldModel withModel:newModel section:section];
        if (indexPath && ![self loadModel:newModel forIndexPath:indexPath replace:NO])
        {
            [indexPaths addObject:indexPath];
        }
    }
    if (indexPaths.count > 0)
    {
        [_table reloadRowsAtIndexPaths:indexPaths withRowAnimation:_rowAnimation];
    }
}

- (void)reloadSection:(NSInteger)section withModelList:(NSArray *)modelList
{
    [self.dataConfig setModelList:modelList forSection:section];
//    if (self.table.numberOfSections > 1)
//    {
//        [self.table reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationNone];
//    }
//    else
//    {
        [self reloadData];
//    }
   
    //    if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.3)
    //    {
    //        [self.dataConfig setModelList:modelList forSection:section];
    //        [self reloadData];
    //    }
    //    else
    //    {
    //        NSArray * originList = [self.dataConfig dataArrayOfSection:section];
    //        if (originList.count != modelList.count)
    //        {
    //            [self.dataConfig setModelList:modelList forSection:section];
    //            [self reloadData];
    //        }
    //        else
    //        {
    //            [self reloadModelList:originList replace:modelList section:section];
    //        }
    //    }
}

- (void)reloadWithDataArrayList:(NSArray<NSArray *> *)dataArrayList
{
    [self cleanData];
    for (NSInteger index = 0; index < dataArrayList.count; index++)
    {
        NSMutableArray * dataArray = [NSMutableArray arrayWithArray:dataArrayList[index]];
        [_sectionDict setObject:[NSMutableArray arrayWithArray:dataArray] forKey:[NSString stringWithFormat:@"%d",(int)index]];
    }
    [_table reloadData];
}

- (void)selectObject:(id)object animated:(BOOL)animated position:(UITableViewScrollPosition)position
{
    [_table selectRowAtIndexPath:[self indexPathForModel:object] animated:animated scrollPosition:position];
}

- (void)deSelectObject:(id)object animated:(BOOL)animated
{
    [_table deselectRowAtIndexPath:[self indexPathForModel:object] animated:animated];
}

#pragma mark TableView Delegate
//UITableViewCell
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return [_sectionDict count];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [(NSMutableArray *)[_sectionDict objectForKey:[NSString stringWithFormat:@"%d",(int)section]] count];
}

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    KExecuteBlock([cell kConfigBlock]);
    if ([cell respondsToSelector:@selector(willDisplayCell)])
    {
        [(UITableViewCell<KTableDataCellProtocol> *)cell willDisplayCell];
    }
}

- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath
{
    if ([cell respondsToSelector:@selector(didEndDisplayCell)])
    {
        [(UITableViewCell<KTableDataCellProtocol> *)cell didEndDisplayCell];
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    id model = [self modelAtIndexPath:indexPath];
    KCellModelConfig * config = [self cellConfigForModel:model];
    NSString * identifier = [model kCellIdentifier] ?: config.reuseIdentfier;
    NSAssert(identifier.length > 0, @"ReuseIdentifier Can Not Be Null！！！ Model:%@",model);
    UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
    if (self.configure.noCellSelectionStyle)
    {
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
    }
    KCellConfigBlock configBlock = [model kCellConfigBlock] ?: config.configBlock;
    if (configBlock)
    {
        CGFloat rowHeight = [model kCellHeight] != nil ? [[model kCellHeight] floatValue] : config.rowHeight;
        if (rowHeight != UITableViewAutomaticDimension)
        {
            __weak UITableViewCell * wcell = cell;
            [cell setKConfigBlock:^{
                __strong UITableViewCell * scell = wcell;
                configBlock(scell,model,indexPath);
            }];
        }
        else
        {
            [cell setKConfigBlock:nil];
            configBlock(cell,model,indexPath);
        }
    }
    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    id model = [self modelAtIndexPath:indexPath];
    KCellSelectBlock selectBlock = [model kCellSelectBlock] ?: [self cellConfigForModel:model].selectBlock;
    KExecuteBlock(selectBlock, model, indexPath);
}

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(nonnull NSIndexPath *)indexPath
{
    id model = [self modelAtIndexPath:indexPath];
    return [model kCellHeight] != nil ? [[model kCellHeight] floatValue] : [self cellConfigForModel:model].estimatedRowHeight;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    id model = [self modelAtIndexPath:indexPath];
    return [model kCellHeight] != nil ? [[model kCellHeight] floatValue] : [self cellConfigForModel:model].rowHeight;
}

//Delete
- (nullable NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (self.enableEdit)
    {
        id model = [self modelAtIndexPath:indexPath];
        //        KCellModelConfig * config = [self cellConfigForModel:model];
        return [model kActionList].count > 0 ? [model kActionList] : [self cellConfigForModel:model].actionList;
    }
    return nil;
}

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (self.enableEdit)
    {
        id model = [self modelAtIndexPath:indexPath];
        if (([model kCellCanDelete] && [[model kCellCanDelete] boolValue]) || [model kActionList].count > 0)
        {
            return YES;
        }
        KCellModelConfig * config = [self cellConfigForModel:model];
        return config.canDelete || config.actionList.count > 0;
    }
    return NO;
}

//- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
//{
//    if (self.enableEdit)
//    {
//        id model = [self modelAtIndexPath:indexPath];
//        BOOL canDelete = [model kCellCanDelete] ? [[model kCellCanDelete] boolValue] : [self cellConfigForModel:model].canDelete;
//        return canDelete ? UITableViewCellEditingStyleDelete : UITableViewCellEditingStyleNone;
//    }
//    return UITableViewCellEditingStyleNone;
//}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (editingStyle == UITableViewCellEditingStyleDelete)
    {
        id model = [self modelAtIndexPath:indexPath];
        KCellDeleteConfirmBlock confirmBlock = [model kCellDeleteConfirmBlock] ?: [[self cellConfigForModel:model] deleteConfirmBlock];
        BOOL canDelete = YES;
        if (confirmBlock) {
            canDelete = confirmBlock(model, indexPath);
        }
//        KExecuteReturnBlock(confirmBlock, YES, model, indexPath);
        if (canDelete)
        {
            [self.operation removeObject:model inSection:indexPath.section];
        }
    }
}

- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return @"删除";
}

//Move
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (self.enableEdit)
    {
        id model = [self.dataConfig modelAtIndexPath:indexPath];
        return [model kCellCanMove] != nil ? [[model kCellCanMove] boolValue] : [self cellConfigForModel:model].canMove;
    }
    return NO;
}

- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
    [self moveModelAtIndexPath:sourceIndexPath toIndexPath:destinationIndexPath];
}

//Section Header
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    id model = [self modelAtSection:section];
    if (model)
    {
        KSectionModelConfig * config = [self sectionHeaderConfigForModel:model];
        NSString * reuseIdentifier = [model kSectionHeaderIdentifier] ?: config.reuseIdentfier;
        if (reuseIdentifier.length > 0)
        {
            UITableViewHeaderFooterView * view = [tableView dequeueReusableHeaderFooterViewWithIdentifier:reuseIdentifier];
            KSectionConfigBlock configBlock = [model kSectionHeaderConfigBlock] ?: config.configBlock;
            KExecuteBlock(configBlock, view, model, section);
            return view;
        }
    }
    return nil;
}

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForHeaderInSection:(NSInteger)section
{
    return [self tableView:tableView heightForHeaderInSection:section];
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    id model = [self modelAtSection:section];
    if (model)
    {
        return [model kSectionHeaderHeight] != nil ? [[model kSectionHeaderHeight] floatValue] : [[self sectionHeaderConfigForModel:model] viewHeight];
    }
    return 0.0f;
}

//Section Footer
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
    id model = [self modelAtSection:section];
    if (model)
    {
        KSectionModelConfig * config = [self sectionFooterConfigForModel:model];
        NSString * reuseIdentifier = [model kSectionFooterIdentifier] ?: config.reuseIdentfier;
        if (reuseIdentifier.length > 0)
        {
            UITableViewHeaderFooterView * view = [_table dequeueReusableHeaderFooterViewWithIdentifier:reuseIdentifier];
            KSectionConfigBlock configBlock = [model kSectionFooterConfigBlock] ?: config.configBlock;
            KExecuteBlock(configBlock, view, model, section);
            return view;
        }
    }
    return nil;
}

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForFooterInSection:(NSInteger)section
{
    return [self tableView:tableView heightForFooterInSection:section];
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
    id model = [self modelAtSection:section];
    if (model)
    {
        return [model kSectionFooterHeight] != nil ? [[model kSectionFooterHeight] floatValue] : [[self sectionFooterConfigForModel:model] viewHeight];
    }
    return 0.0f;
}

- (NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
    if (self.enableIndexTitles)
    {
        NSMutableArray<NSString *> * indexTitles = [NSMutableArray arrayWithCapacity:_sectionModelDict.count];
        for (int index = 0; index < _sectionModelDict.count; index++)
        {
            id sectionModel = [self modelAtSection:index];
            if ([sectionModel kSectionIndexTitle].length > 0)
            {
                [indexTitles addObject:[sectionModel kSectionIndexTitle]];
            }
        }
        return indexTitles;
    }
    return nil;
}

- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
    for (int index = 0; index < _sectionModelDict.count; index++)
    {
        id sectionModel = [self modelAtSection:index];
        if ([[sectionModel kSectionIndexTitle] isEqualToString:title])
        {
            return index;
        }
    }
    return 0;
}

#pragma mark 代理消息转发

- (BOOL)respondsToSelector:(SEL)aSelector
{
    return [super respondsToSelector:aSelector] || [_outDelegate respondsToSelector:aSelector] || [_outDataSource respondsToSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    if ([_outDelegate respondsToSelector:anInvocation.selector])
    {
        [anInvocation invokeWithTarget:_outDelegate];
    }
    else if ([_outDataSource respondsToSelector:anInvocation.selector])
    {
        [anInvocation invokeWithTarget:_outDataSource];
    }
    else if ([super respondsToSelector:anInvocation.selector])
    {
        [super forwardInvocation:anInvocation];
    }
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    NSMethodSignature * sig = nil;
    if ((sig = [_outDelegate methodSignatureForSelector:aSelector]))
    {
        return sig;
    }
    if ((sig = [_outDataSource methodSignatureForSelector:aSelector]))
    {
        return sig;
    }
    return [super methodSignatureForSelector:aSelector];
}

@end

//- (BOOL)respondsToSelector:(SEL)aSelector
//{
//    NSString * selName = NSStringFromSelector(aSelector);
//    if ([selName hasPrefix:KTableDataSelPrefix])
//    {
//        if ([super respondsToSelector:aSelector])
//        {
//            return YES;
//        }
//        SEL normalSelector = NSSelectorFromString([selName stringByReplacingCharactersInRange:NSMakeRange(0, KTableDataSelPrefix.length) withString:@""]);
//        return [_outDelegate respondsToSelector:normalSelector] || [_outDataSource respondsToSelector:normalSelector];
//    }
//    else
//    {
//        if ([_extendDelegate respondsToSelector:aSelector])
//        {
//            return YES;
//        }
//        SEL ownSelector = NSSelectorFromString([KTableDataSelPrefix stringByAppendingString:selName]);
//        if ([self respondsToSelector:ownSelector])
//        {
//            return YES;
//        }
//    }
//    return [_outDelegate respondsToSelector:aSelector] || [_outDataSource respondsToSelector:aSelector];
//}

//- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
//{
//    NSMethodSignature * sig = nil;
//    NSString * selName = NSStringFromSelector(aSelector);
//    if ([selName hasPrefix:KTableDataSelPrefix])
//    {
//        SEL normalSelector = NSSelectorFromString([selName stringByReplacingCharactersInRange:NSMakeRange(0, KTableDataSelPrefix.length) withString:@""]);
//        if ((sig = [_outDelegate methodSignatureForSelector:normalSelector]))
//        {
//            return sig;
//        }
//        if ((sig = [_outDataSource methodSignatureForSelector:normalSelector]))
//        {
//            return sig;
//        }
//    }
//    else
//    {
//        if ((sig = [_extendDelegate methodSignatureForSelector:aSelector]))
//        {
//            return sig;
//        }
//        if ((sig = [super methodSignatureForSelector:NSSelectorFromString([KTableDataSelPrefix stringByAppendingString:selName])]))
//        {
//            return sig;
//        }
//        if ((sig = [_outDelegate methodSignatureForSelector:aSelector]))
//        {
//            return sig;
//        }
//        if ((sig = [_outDataSource methodSignatureForSelector:aSelector]))
//        {
//            return sig;
//        }
//    }
//    return [super methodSignatureForSelector:aSelector];
//}

//- (void)forwardInvocation:(NSInvocation *)anInvocation
//{
//    NSString * selName = NSStringFromSelector(anInvocation.selector);
//    if ([selName hasPrefix:KTableDataSelPrefix])
//    {
//        SEL normalSelector = NSSelectorFromString([selName stringByReplacingCharactersInRange:NSMakeRange(0, KTableDataSelPrefix.length) withString:@""]);
//        anInvocation.selector = normalSelector;
//    }
//    else
//    {
//        if ([_extendDelegate respondsToSelector:anInvocation.selector])
//        {
//            [anInvocation invokeWithTarget:_extendDelegate];
//            return;
//        }
//        SEL ownSelector = NSSelectorFromString([KTableDataSelPrefix stringByAppendingString:selName]);
//        if ([self respondsToSelector:ownSelector])
//        {
//            anInvocation.selector = ownSelector;
//            [anInvocation invokeWithTarget:self];
//            return;
//        }
//    }
//    if ([_outDelegate respondsToSelector:anInvocation.selector])
//    {
//        [anInvocation invokeWithTarget:_outDelegate];
//    }
//    else if ([_outDataSource respondsToSelector:anInvocation.selector])
//    {
//        [anInvocation invokeWithTarget:_outDataSource];
//    }
//    else
//    {
//        [super forwardInvocation:anInvocation];
//    }
//}
